package com.beasts.ant.auth.config.oauth.filter;

import com.beasts.ant.auth.common.constant.CommonConstant;
import com.beasts.ant.auth.common.constant.SecurityConstants;
import com.beasts.ant.auth.common.dto.R;
import com.beasts.ant.auth.common.exception.ValidateCodeException;
import com.beasts.ant.auth.utils.StringUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 验证码校验，true开启，false关闭校验
 * TODO 更细化可以 clientId 进行区分
 *
 * @author Locker
 * @date 07/05/2018 4:05 PM
 * @since 1.0
 */
@Component("validateCodeFilter")
public class ValidateCodeFilter extends OncePerRequestFilter {

    @Value("${security.validate.code:true}")
    private boolean isValidate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse resp, FilterChain filterChain) throws ServletException, IOException {
        if (isValidate
                && StringUtil.contains(req.getRequestURI(), SecurityConstants.OAUTH_TOKEN_URL)
                || StringUtil.contains(req.getRequestURI(), SecurityConstants.REFRESH_TOKEN)) {
            PrintWriter printWriter = null;
            try {
                checkCode(req, resp, filterChain);
            } catch (ValidateCodeException e) {
                resp.setCharacterEncoding(CommonConstant.UTF8);
                resp.setContentType(CommonConstant.CONTENT_TYPE);
                R<String> result = new R<>(e);
                resp.setStatus(478);
                printWriter = resp.getWriter();
                printWriter.append(objectMapper.writeValueAsString(result));
            } finally {
                // TODO 可换 commons-io 2.5
                IOUtils.closeQuietly(printWriter);
            }
        } else {
            filterChain.doFilter(req, resp);
        }
    }

    private void checkCode(HttpServletRequest req, HttpServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
        String code = req.getParameter("code");
        String randomStr = req.getParameter("randomStr");

        // 移动端登录
//        if (StringUtil.isBlank(randomStr)) {
//            randomStr = req.getParameter("mobile");
//        }

        // 从 redis 中获取 token
        Object codeObj = redisTemplate.opsForValue().get(SecurityConstants.DEFAULT_CODE_KEY + randomStr);
        if (codeObj == null) {
            throw new ValidateCodeException("验证码为空或已过期");
        }

        String saveCode = codeObj.toString();

        if (StringUtil.isBlank(code)) {
            redisTemplate.delete(SecurityConstants.DEFAULT_CODE_KEY + randomStr);
            throw new ValidateCodeException("验证码的值不能为空");
        }

        if (StringUtil.isEmpty(saveCode)) {
            redisTemplate.delete(SecurityConstants.DEFAULT_CODE_KEY + randomStr);
            throw new ValidateCodeException("验证码已过期或已过期");
        }

        if (!StringUtil.equals(saveCode, code)) {
            redisTemplate.delete(SecurityConstants.DEFAULT_CODE_KEY + randomStr);
            throw new ValidateCodeException("验证码不匹配");
        }

        if (StringUtil.equals(code, saveCode)) {
            redisTemplate.delete(SecurityConstants.DEFAULT_CODE_KEY + randomStr);
            filterChain.doFilter(req, resp);
        }

    }

}
